/**
 * Created by Administrator on 2017/8/30.
 */
namespace game {
    export class HashMap<T,S> {
        private _keyToValue:Map<T,S>;
        private _valueToKey:Map<S,T>;
        private _keyList:T[];
        private _toArrayList:S[];

        public constructor() {
            this._keyToValue = new Map<T,S>();
            this._valueToKey = new Map<S,T>();
            this._keyList = [];
            this._toArrayList = [];
        }

        public valueForEach(callbackfn: (value: S, key: T, map: Map<T, S>) => void, thisArg?: any)
        {
            this._keyToValue.forEach(callbackfn,thisArg);
        }

        public keyForEach(callbackfn: (value: T, key: S, map: Map<S, T>) => void, thisArg?: any)
        {
            this._valueToKey.forEach(callbackfn,thisArg);
        }

        public hasByKey(key)
        {
            return this._keyToValue.has(key);
        }

        public set(key,value)
        {
            this._keyToValue.set(key,value);
            this._valueToKey.set(value,key);
            this._keyList.push(key);
            this.setChanged();
        }

        public getValueByKey(key)
        {
            return this._keyToValue.get(key);
        }

        public getKeyByValue(value)
        {
            return this._valueToKey.get(value);
        }

        public getValueByIndex(index)
        {
            let key = this._keyList[index];
            return this.getValueByKey(key);
        }

        public toArray(){
            if(this._toArrayList.length == 0){
                for(let i = 0;i<this._keyList.length;i++){
                    this._toArrayList.push(this._keyToValue.get(this._keyList[i]));
                }
            }
            return this._toArrayList;
        }

        public removeByKey(key)
        {
            let v = this._keyToValue.get(key);
            this._keyToValue.delete(key);
            this._valueToKey.delete(v);
            let idx = this._keyList.indexOf(key);
            if(idx>=0)
                this._keyList.splice(idx,1);
            this.setChanged();
        }

        public setChanged(){
            this._toArrayList.length = 0;
        }

        public get size()
        {
            return this._keyToValue.size;
        }

        public sort(compareFn:Function)
        {
            let map = this;
            this._keyList = this._keyList.sort((a,b):number=>
            {
               let valueA = map.getValueByKey(a);
               let valueB = map.getValueByKey(b);
               return compareFn(valueA,valueB);
            });
        }

        public filter(filterFn:Function)
        {
            let valueList:S[] = [];
            for(let i = 0;i<this._keyList.length;i++)
            {
                let value = this.getValueByKey(this._keyList[i]);
                if(!filterFn || filterFn(value))
                    valueList.push(value);
            }
            return valueList;
        }

        public some(checkFuc:(value:S)=>boolean){
            for(let i = 0;i<this._keyList.length;i++){
                let value = this.getValueByKey(this._keyList[i]);
                if(value && checkFuc(value)){
                    return true;
                }
            }
            return false;
        }

        public shift():S{
            let key = this._keyList[0];
            let v = this._keyToValue.get(key);
            this.removeByKey(key);
            return v;
        }
    }
}